import {
	isPlainObject
} from "./reactive/utils.js";
/**
 * 首先，WeakMap只接受对象作为键名（null除外），不接受其他类型的值作为键名;
 * 其次，WeakMap的键名所指向的对象，不计入垃圾回收机制;
 */
const observable = new WeakMap();

let activeEffect;
let effectStack = [];

const convert = (target) => {
	return isPlainObject(target) ? reactive(target) : target;
}

class RefImpl {
	constructor() {

	}
}

class ObjectRefImpl {
	constructor(_object, _key) {
		this._object = _object;
		this._key = _key;
		this.__v_isRef = true;
	}
	get value() {
		return this._object[this._key];
	}
	set value(newVal) {
		this._object[this._key] = newVal;
	}
}

const track = (target, propKey) => {
	const activeEffect = effectStack[effectStack.length - 1];
	if (activeEffect) {
		let depMap = observable.get(target);

		if (depMap === undefined) {
			observable.set(target, depMap = new Map());
		}

		let deps = depMap.get(propKey);

		if (deps === undefined) {
			depMap.set(propKey, deps = new Set());
		}

		if (deps.has(activeEffect) === false) {
			deps.add(activeEffect);
		}
	}
}

const trigger = (target, type, propKey) => {
	const depMap = observable.get(target);
	if (!depMap) return;
	const deps = depMap.get(propKey);
	for (const callback of deps || []) {
		callback(target[propKey]);
	}
}

const handler = {
	set(target, propKey, value, receiver) {
		let isModifiedSuccess = true;
		const oldValue = Reflect.get(target, propKey, receiver);
		console.log('set propKey', propKey, value);

		if (oldValue !== value) {
			trigger(target, 'set', propKey); // 收集依赖
			isModifiedSuccess = Reflect.set(target, propKey, value, receiver);
		}
		return isModifiedSuccess;
	},
	get(target, propKey, receiver) {
		console.log('get propKey', propKey, 'track');

		/**
		 * 此处需要递归处理，否则搜集不到深层属性的依赖
		 */

		track(target, propKey); // 触发事件
		return convert(Reflect.get(target, propKey, receiver));
	},
	deleteProperty(target, propKey) {
		const isDeletedSuccess = Reflect.deleteProperty(target, propKey);
		if (isDeletedSuccess) {
			console.log(isDeletedSuccess);
			// trigger(target, 'delete', propKey); // 收集依赖
		}
		return isDeletedSuccess;
	}
}

const createReactiveEffect = (callback, options) => {
	const effect = function () {
		return run(effect, callback);
	}

	effect.lazy = options.lazy;
	effect.computed = options.computed;

	return effect;
}

const run = (effect, callback) => {
	if (!effectStack.includes(effect)) {
		try {
			/**
			 * 在执行callback函数，进行属性访问
			 * 进行搜集依赖前，将事件推进effectStack
			 * 以便进行搜集依赖
			 */
			effectStack.push(effect);
			return callback();
		} finally {
			/**
			 * 执行完毕后再移除元素
			 * 避免callback函数中使用多个响应数据属性
			 * 在搜集依赖时，获取不到callback的包裹函数
			 */
			effectStack.pop();
		}
	}
}

const effect = (callback, options = {}) => {
	const activeEffect = createReactiveEffect(callback, options)
	if (!options.lazy) {
		activeEffect()
	}

	return activeEffect;
}

const computed = (callback) => {
	const runner = effect(callback, {
		computed: true,
		lazy: true
	});
	return {
		effect: runner,
		get value() {
			return runner();
		}
	}
}

const reactive = (target) => {
	return new Proxy(target, handler);
}

function isRef(r) {
	return Boolean(r && r.__v_isRef === true);
}

const ref = (raw) => {
	console.log(raw);
}

export {
	reactive,
	handler,
	effect,
	computed,
	ref
}